"""
文件上传器小部件。
"""
import typing
from ..base import BaseSession, BaseSessionType, BaseSessionParentType
from .base import BaseTextWidget
from ..framework import dispatch, session_received
from ..utils import callback, from_any, to_any, Any, FloatValue, StringValue


@session_received
class WidgetFileUploader(BaseSession, BaseTextWidget):
    """
    文件上传器小部件。
    """
    name = 'WidgetFileUploader'

    @classmethod
    async def create(
            cls: typing.Type[BaseSessionType], parent: BaseSessionParentType, *args: typing.Any, **kwargs: typing.Dict
    ) -> BaseSessionType:
        """
        五个参数：
        @width: 宽度；
        @height: 高度；
        @x: 左上角横坐标；
        @y: 左上角纵坐标；
        @text: 上传器的文字内容（可选，默认为None）
        使用方法：
        uploader = await WidgetFileUploader.create(activity, 200, 50, 0, 0, '请选择文件')
        """
        return await super().create(parent, *cls.parse_region_and_text(*args), **kwargs)

    async def on_receive(self, msg):
        """
        组件的事件转发。
        """
        await super().on_receive(msg)
        name, sid, fid = msg.name, msg.session, msg.future
        if name == 'onGetMimeType':
            dispatch(self.on_get_mime_type(*msg.argv, session_id=sid, future_id=fid))
        elif name == 'onGetFilename':
            dispatch(self.on_get_filename(*msg.argv, session_id=sid, future_id=fid))
        elif name == 'onUpload':
            dispatch(self.on_upload(*msg.argv, session_id=sid, future_id=fid))
        else:
            dispatch(super().on_widget_action(*msg.argv, name=name, session_id=sid, future_id=fid))

    @callback(str)
    async def on_get_mime_type(self, mime_type, session_id=0, future_id=0):
        """
        当获取上传器文件类型成功后，此方法被自动调用。
        通常不需要关注此方法的实现。
        """
        if not session_id:
            return
        self.set_action_result(session_id, future_id, mime_type)

    async def set_mime_type(self, mime_type: typing.Optional[str] = None):
        """
        设置文件类型。
        :param mime_type: 文件类型。
        使用示例：
        await uploader.set_mime_type('audio/*')
        """
        dispatch(self.send_action('setMimeType', to_any(mime_type, StringValue)))

    async def get_mime_type(self) -> typing.Optional[str]:
        """
        获取文件类型。
        使用示例：
        print(await uploader.get_mime_type())
        """
        return await self.send_action_until_return('getMimeType')

    @callback(str)
    async def on_get_filename(self, filename, session_id=0, future_id=0):
        """
        当获取上传器文件名成功后，此方法被自动调用。
        通常不需要关注此方法的实现。
        """
        if not session_id:
            return
        self.set_action_result(session_id, future_id, filename)

    @callback(bool)
    async def on_upload(self, result, session_id=0, future_id=0):
        """
        当上传器完成上传文件后，此方法被自动调用。
        通常不需要关注此方法的实现。
        """
        if not session_id:
            return
        self.set_action_result(session_id, future_id, result)

    async def get_filename(self) -> typing.Optional[str]:
        """
        获取文件名称。
        使用示例：
        print(await uploader.get_filename())
        """
        return await self.send_action_until_return('getFilename')

    async def upload(self, url: str, func: typing.Optional[typing.Callable] = None):
        """
        开始上传文件。
        :param url: 接收的url，需实现web标准的文件上传接口。
        :param func: 监听进度事件的异步函数（函数需实现一个参数progress: float），可以为None，如果是None则不接收上传进度。
        """
        if not func:
            return await self.send_action_until_return('upload', to_any(url, StringValue), to_any(None))

        async def inner(progress: Any):
            """
            内部使用。
            """
            await func(from_any(progress, FloatValue))

        return await self.send_action_until_return('upload', to_any(url, StringValue), self.create_callback(inner))
